home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
pluginy Firefox
/
722
/
722.xpi
/
chrome
/
noscript.jar
/
content
/
noscript
/
ClearClickHandler.js
< prev
next >
Wrap
Text File
|
2010-02-12
|
30KB
|
947 lines
function ClearClickHandler(ns) {
this.ns = ns;
if (ns.geckoVersionCheck("1.9.2") < 0)
INCLUDE("ClearClickHandlerLegacy");
}
ClearClickHandler.prototype = {
// TODO:
// 1. try to use MozAfterPaint (Fx 3.1) to intercept "Sudden Reveal" attacks
// 2. try to use http://www.oxymoronical.com/experiments/apidocs/interface/nsIDOMWindowUtils:compareCanvases
uiEvents: ["mousedown", "mouseup", "click", "dblclick", "keydown", "keypress", "keyup", "blur"],
install: function(browser) {
var ceh = browser.docShell.chromeEventHandler;
var l = this._listener;
for each(var et in this.uiEvents) ceh.addEventListener(et, this._listener, true);
},
exceptions: null,
get _listener() {
var self = this;
var l = function(ev) { self.handle(ev); };
this.__defineGetter__("_listener", function() { return l; });
},
sameSiteParents: function(w) {
const ns = this.ns;
var site = ns.getSite(w.location.href);
if (site == "about:blank") site = "";
var parentSite;
for(var p = w.parent; p != w; w = p, p = w.parent) {
parentSite = ns.getSite(p.location.href);
if (!site || /^(?:chrome|resource|about):/.test(parentSite)) {
site = parentSite;
continue;
}
if (site != parentSite) return false;
}
if (ns.consoleDump & LOG_CLEARCLICK) ns.dump("ClearClick skipping, same site parents for " + site);
return true;
},
appliesHere: function(url) {
const ns = this.ns;
return ns.appliesHere(ns.clearClick, url) &&
!(this.exceptions && this.exceptions.test(url) && ns.isJSEnabled(ns.getSite(url)));
},
checkSubexception: function(url) {
return this.subexceptions && this.subexceptions.test(url);
},
_whitelist: {},
whitelistLen: 0,
isWhitelisted: function(w) {
var l = this._whitelist[w.location.href];
if (!l) return false;
var pp = [];
for(var p = w.parent; p != w; w = p, p = w.parent) {
pp.push(p.location.href);
}
return l.indexOf(pp.join(" ")) > -1;
},
whitelist: function(w) {
if (this.isWhitelisted(w)) return;
var u = w.location.href;
var pp = [];
for(var p = w.parent; p != w; w = p, p = w.parent) {
pp.push(p.location.href);
}
var l;
if (u in this._whitelist) l = this._whitelist[u];
else {
l = this._whitelist[u] = [];
this.whitelistLen++;
}
l.push(pp.join(" "));
},
resetWhitelist: function() {
this._whitelist = {};
this.whitelistLen = 0;
},
isEmbed: function(o) {
return (o instanceof CI.nsIDOMHTMLObjectElement || o instanceof CI.nsIDOMHTMLEmbedElement)
&& !o.contentDocument && ns.isWindowlessObject(o);
},
swallowEvent: function(ev) {
ev.cancelBubble = true;
ev.stopPropagation();
ev.preventDefault();
},
_zoom: 1,
getBox: function(o, d, w) {
if (!d) d = o.ownerDocument;
if (!w) w = d.defaultView;
var c = o.getBoundingClientRect();
var x = c.left, y = c.top; // this is relative to the view port, just like mozInnerScreen*
return {
x: x + w.scrollX, y: y + w.scrollY, // add scroll* to make it absolute
width: c.width, height: c.height,
screenX: w.mozInnerScreenX + x, screenY: w.mozInnerScreenY + y
}
},
getBG: function(w) {
var bg = w.document.body && w.getComputedStyle(w.document.body, '').backgroundColor || "white";
return bg == "transparent" ? w != w.parent && this.getBG(w.parent) || "white" : bg;
},
_constrain: function(box, axys, dim, max, vp, center) {
var d;
var scr = "screen" + axys.toUpperCase();
// trim bounds to take in account fancy overlay borders
var l = box[dim];
var n = box[axys];
if (vp.frame && center && l < vp[dim]) { // expand to viewport if possible
l = vp[dim];
}
if (l > 6) {
var bStart = Math.floor(l * .1) // 20% border
var bEnd = bStart;
if (bStart + n > center) {
bStart = center - n;
} else if (l + n - center < bEnd) {
bEnd = l + n - center;
}
box[dim] = (l -= (bStart + bEnd));
box[axys] = (n += bStart);
box[scr] += bStart;
}
if (l > max) {
// resize
if (center) {
var halfMax = Math.round(max / 2);
var nn = center - halfMax;
if (nn > n && center + halfMax > n + l) nn = (n + l) - max;
box[axys] = nn;
box[scr] += (nn - n);
n = nn;
}
l = box[dim] = max;
}
// slide into viewport
var vpn = vp[axys];
d = (n < vpn)
? vpn - n
: (n + l) > (vpn + vp[dim])
? (vpn + vp[dim]) - (n + l)
: 0;
if (d) {
n = (box[axys] += d);
box[scr] += d;
}
},
createCanvas: function(doc) {
return doc.__clearClickCanvas || (doc.__clearClickCanvas = doc.createElementNS(HTML_NS, "canvas"));
},
isSupported: function(doc) {
return true;
},
_semanticContainers: [CI.nsIDOMHTMLParagraphElement, CI.nsIDOMHTMLQuoteElement,
CI.nsIDOMHTMLUListElement, CI.nsIDOMHTMLOListElement, CI.nsIDOMHTMLDirectoryElement,
CI.nsIDOMHTMLPreElement, CI.nsIDOMHTMLTableElement ]
,
isSemanticContainer: function(o) {
for each (var t in this._semanticContainers)
if (o instanceof t) return true;
return false;
},
forLog: function(o) {
return o.tagName + "/" + (o.tabIndex || 0);
},
handle: function(ev) {
const o = ev.target;
const d = o.ownerDocument;
if (!(d && this.isSupported(d))) return;
const w = d.defaultView;
if (!w) return;
const top = w.top;
const ns = this.ns;
var isEmbed;
if (top.__clearClickUnlocked || (top.__clearClickUnlocked = !this.appliesHere(top.location.href)) ||
o.__clearClickUnlocked ||
o != ev.originalTarget ||
o == d.documentElement || o == d.body || // key event on empty region
this.isSemanticContainer(o) ||
(o.__clearClickUnlocked = !(isEmbed = this.isEmbed(o)) && // plugin embedding?
(w == w.top || w.__clearClickUnlocked ||
(w.__clearClickUnlocked = this.isWhitelisted(w))
|| this.sameSiteParents(w)) || // cross-site document?
ns.getPluginExtras(o) || // NS placeholder?
this.checkSubexception(isEmbed && (o.src || o.data) || w.location.href)
)
) return;
var p = ns.getExpando(o, "clearClickProps", {});
var verbose = ns.consoleDump & LOG_CLEARCLICK;
var etype = ev.type;
if (verbose) ns.dump(o.tagName + ", " + etype + ", " + p.toSource());
var ts = 0, obstructed, ctx, primaryEvent;
try {
if (etype == "blur") {
if(/click|key/.test(p.lastEtype)) {
if (verbose) ns.dump("ClearClick: resetting status on " + this.forLog(o) + " for " + etype);
if (p.unlocked) p.unlocked = false;
}
return;
}
if (p.unlocked) return;
ts = Date.now();
ctx = /mouse/.test(etype)
&& { x: ev.pageX, y: ev.pageY, debug: ev.ctrlKey && ev.button == 1 && ns.getPref("clearClick.debug") }
|| {};
ctx.isEmbed = isEmbed;
primaryEvent = /^(?:mousedown|keydown)$/.test(etype) ||
// submit button generates a syntethic click if any text-control receives [Enter]: we must consider this "primary"
etype == "click" && ev.screenX == 0 && ev.screenY == 0 && ev.pageX == 0 && ev.pageY == 0 && ev.clientX == 0 && ev.clientY == 0 && ev.target.form &&
((ctx.box = this.getBox(ev.target, d, w)).screenX * ctx.box.screenY != 0) ||
// allow infra-document drag operations and tabulations
etype != "blur" && top.__clearClickDoc == d && (top.__clearClickProps.unlocked || top.__clearClickProps.lastEtype == "blur");
obstructed = (primaryEvent || !("obstructed" in p))
? p.obstructed = this.checkObstruction(o, ctx)
: p.obstructed; // cache for non-primary events
} catch(e) {
ns.dump(e.message + ": " + e.stack);
obstructed = true;
} finally {
p.lastEtype = etype;
top.__clearClickProps = p;
top.__clearClickDoc = d;
}
var quarantine = ts - (p.ts || 0);
if (verbose) ns.dump("ClearClick: " + ev.target.tagName + " " + etype +
"(s:{" + ev.screenX + "," + ev.screenY + "}, p:{" + ev.pageX + "," + ev.pageY + "}, c:{" + ev.clientX + "," + ev.clientY +
", w:" + ev.which + "}) - obstructed: " + obstructed + ", check time: " + (new Date() - ts) + ", quarantine: " + quarantine +
", primary: " + primaryEvent + ", ccp:" + (top.__clearClickProps && top.__clearClickProps.toSource()));
var unlocked = !obstructed && primaryEvent && quarantine > 3000;
if (unlocked) {
if (verbose) ns.dump("ClearClick: unlocking " + ev.target.tagName + " " + etype);
p.unlocked = true;
} else {
this.swallowEvent(ev);
ns.log("[NoScript ClearClick] Swallowed event " + etype + " on " + this.forLog(o) + " at " + w.location.href, true);
var docShell = DOM.getDocShellForWindow(w);
var loading = docShell && (docShell instanceof CI.nsIWebProgress) && docShell.isLoadingDocument;
if (!loading) {
p.ts = ts;
if (primaryEvent && ctx.img && ns.getPref("clearClick.prompt") && !this.prompting) {
try {
this.prompting = true;
var params = {
url: isEmbed && (o.src || o.data) || o.ownerDocument.URL,
pageURL: w.location.href,
topURL: w.top.location.href,
img: ctx.img,
locked: false,
pageX: ev.pageX,
pageY: ev.pageY,
zoom: this._zoom
};
DOM.findBrowserForNode(w).ownerDocument.defaultView.openDialog(
"chrome://noscript/content/clearClick.xul",
"noscriptClearClick",
"chrome, dialog, dependent, centerscreen, modal",
params);
if (!params.locked) {
w.__clearClickUnlocked = o.__clearClickUnlocked = true
this.whitelist(w);
}
} finally {
this.prompting = false;
}
}
}
}
},
findParentForm: function(o) {
var ftype = CI.nsIDOMHTMLFormElement;
while((o = o.parentNode)) {
if (o instanceof ftype) return o;
}
return null;
},
rndColor: function() {
var c = Math.round(Math.random() * 0xffffff).toString(16);
return "#" + ("000000".substring(c.length)) + c;
},
maxWidth: 350,
maxHeight: 200,
minWidth: 160,
minHeight: 100,
_NO_SCROLLBARS: {w: 0, h: 0},
computeScrollbarSizes: function(frame, dElem, body) {
var fw = frame.clientWidth, fh = frame.clientHeight;
var dw = dElem.clientWidth, dh = dElem.clientHeight;
var w = Math.min(fw, dw), h = Math.min(fh, dh);
if (body) {
var bw = body.clientWidth;
var bh = body.clientHeight;
if (bw <= fw && (bw - dw > 24 || dw > fw)) w = bw;
if (bh <= fh && (bh - dh > 24 || dh > fh)) h = bh;
}
return { w: fw - w, h: fh - h };
},
checkObstruction: function(o, ctx) {
var d = o.ownerDocument;
var dElem = d.documentElement;
var w = d.defaultView;
var top = w.top;
var browser = DOM.findBrowserForNode(top);
var c = this.createCanvas(browser.ownerDocument);
var gfx = c.getContext("2d");
var bg = this.getBG(w);
var bgStyle;
var box, curtain;
var frame, frameClass, frameStyle, objClass, viewer;
var docPatcher = new DocPatcher(this.ns, o, w);
var sheet = null;
var img1 = null, img2 = null, tmpImg = null;
function snapshot(w, x, y) {
gfx.drawWindow(w, Math.round(x), Math.round(y), c.width, c.height, bg);
return c.toDataURL();
}
function snapshots(x1, y1, x2, y2) {
img1 = null;
try {
if (objClass) docPatcher.clean(true);
img1 = snapshot(w, x1, y1);
} catch(ex) {
throw ex;
} finally {
docPatcher.clean(false);
}
img2 = tmpImg = snapshot(top, x2, y2);
return (img1 != img2);
}
var sd = this._NO_SCROLLBARS;
try {
docPatcher.linkAlertHack(true);
docPatcher.fbPresenceHack(true);
try {
docPatcher.opaque(true);
var fbPresence; // hack for Facebooks's fixed positioned widget
if (ctx.isEmbed) { // objects and embeds
if (this.ns.getPref("clearClick.plugins", true)) {
var ds = browser.docShell;
viewer = ds.contentViewer && false;
objClass = new ClassyObj(o);
objClass.append(" __noscriptBlank__");
docPatcher.blankPositioned(true);
docPatcher.clean(true);
} else {
DOM.addClass(o, "__noscriptOpaqued__");
}
}
if ((frame = w.frameElement)) {
frameClass = new ClassyObj(frame);
DOM.removeClass(frame, "__noscriptScrolling__");
sd = this.computeScrollbarSizes(frame, dElem, d.body);
var zoom = d.defaultView.QueryInterface(CI.nsIInterfaceRequestor)
.getInterface(CI.nsIDOMWindowUtils).screenPixelsPerCSSPixel;
sd.w *= zoom;
sd.h *= zoom;
}
var clientHeight = w.innerHeight - sd.h;
var clientWidth = w.innerWidth - sd.w;
// print(dElem.clientWidth + "," + dElem.clientHeight + " - " + w.innerWidth + "," + w.innerHeight);
if (!ctx.isEmbed) {
curtain = d.createElementNS(HTML_NS, "div");
with (curtain.style) {
top = left = "0px";
width = (clientWidth + w.scrollX) + "px";
height = (clientHeight + w.scrollY) + "px";
padding = margin = borderWidth = MozOutlineWidth = "0px";
position = "absolute";
zIndex = "99999999";
background = this.rndColor();
}
frameStyle = w.parent.getComputedStyle(frame, '');
}
if (curtain && frame) {
dElem.appendChild(curtain);
}
var maxWidth = Math.max(Math.min(this.maxWidth, clientWidth), this.minWidth);
var maxHeight = Math.max(Math.min(this.maxHeight, clientHeight), this.minHeight);
box = this.getBox(o, d, w);
// expand to parent form if needed
var form = o.form;
var formBox = null;
if (frame && !ctx.isEmbed && (form || (form = this.findParentForm(o)))) {
formBox = this.getBox(form, d, w);
if (!(formBox.width && formBox.height)) { // some idiots put <form> as first child of <table> :(
formBox = this.getBox(form.offsetParent || form.parentNode, d, w);
if (!(formBox.width && formBox.height)) {
formBox = this.getBox(form.parentNode.offsetParent || o.offsetParent, d, w);
}
}
if (formBox.width && formBox.height) {
ctx.x = ctx.x || box.x + box.width;
ctx.y = ctx.y || box.y + box.height;
box = formBox;
var delta;
if (box.x < 0) {
box.screenX -= box.x;
box.x = 0;
}
if (box.y < 0) {
box.screenY -= box.y;
box.y = 0;
}
if (box.x + Math.min(box.width, maxWidth) < ctx.x) {
box.width = Math.min(box.width, maxWidth);
delta = ctx.x + 4 - box.width - box.x;
box.x += delta;
box.screenX += delta;
}
if (box.y + Math.min(box.height, maxHeight) < ctx.y) {
box.height = Math.min(box.height, maxHeight);
delta = ctx.y + 4 - box.height - box.y;
box.y += delta;
box.screenY += delta;
}
o = form;
}
}
bgStyle = dElem.style.background;
dElem.style.background = bg;
// clip, slide in viewport and trim
var vp = {
x: w.scrollX,
y: w.scrollY,
width: Math.max(w.innerWidth - sd.w, 32),
height: Math.max(w.innerHeight - sd.h, 32),
frame: frame
};
if (ctx.isEmbed) { // check in-page vieport
vp.frame = null;
vp.x = Math.max(vp.x, box.x);
vp.y = Math.max(vp.y, box.y);
vp.width = Math.min(vp.width, box.width);
vp.height = Math.min(vp.height, box.height);
for(form = o; form = form.parentNode;) {
if ((form.offsetWidth < box.width || form.offsetHeight < box.height) &&
w.getComputedStyle(form, '').overflow != "visible") {
// check if we're being fooled by some super-zoomed applet
if (box.width / 4 <= form.offsetWidth && box.height / 4 <= form.offsetHeight) {
formBox = this.getBox(form, d, w);
if (box.x < formBox.x) {
box.x = formBox.x;
box.screenX = formBox.screenX;
}
if (box.y < formBox.y) {
box.y = formBox.y;
box.screenY = formBox.screenY;
}
if (box.width + box.x > formBox.width + formBox.x) box.width = Math.max(this.minWidth, form.clientWidth - (box.x - formBox.x));
if (box.height + box.y > formBox.height + formBox.y) box.height = Math.max(this.minHeight, form.offsetHeight - (box.y - formBox.y));
}
break;
}
}
} else if (!(sd.w || sd.h)) { // no scrollbars
if (!sd.w) {
vp.x = 0;
vp.width = curtain.offsetWidth;
}
if (!sd.h) {
vp.y = 0;
vp.height = curtain.offsetHeight;
}
}
box.oX = box.x;
box.oY = box.y;
box.oW = box.width;
box.oH = box.height;
// print("Fitting " + box.toSource() + " in " + vp.toSource() + " - ctx " + ctx.x + ", " + ctx.y + " - max " + maxWidth + ", " + maxHeight);
this._constrain(box, "x", "width", maxWidth, vp, ctx.x);
this._constrain(box, "y", "height", maxHeight, vp, ctx.y);
// print(box.toSource());
c.width = box.width;
c.height = box.height;
if (this.ns.consoleDump & LOG_CLEARCLICK) this.ns.dump("Snapshot at " + box.toSource() + " + " + w.pageXOffset + ", " + w.pageYOffset);
img1 = snapshot(w, box.x, box.y);
} finally {
docPatcher.clean(false);
}
var rootElement = top.document.documentElement;
var rootBox = this.getBox(rootElement, top.document, top);
var offsetX = (box.screenX - rootBox.screenX);
var offsetY = (box.screenY - rootBox.screenY);
var ret = true;
var tmpImg;
const offs = ctx.isEmbed ? [0] : [0, -1, 1, -2, 2, -3, -3];
checkImage:
for each(var x in offs) {
for each(var y in offs) {
tmpImg = snapshot(top, offsetX + x, offsetY + y);
if (img1 == tmpImg) {
ret = false;
break checkImage;
}
if (!img2) img2 = tmpImg;
}
}
if (ret && !curtain && ctx.isEmbed) {
curtain = d.createElementNS(HTML_NS, "div");
if (docPatcher) curtain.className = docPatcher.shownCS;
with (curtain.style) {
// we expand by 1 pixel in order to avoid antialias effects on the edge at zoom != 1 (GMail Flash attachment)
top = (o.offsetTop - 1) + "px";
left = (o.offsetLeft -1) + "px";
width = (o.offsetWidth +2) + "px";
height = (o.offsetHeight +2) + "px";
position = "absolute";
zIndex = w.getComputedStyle(o, '').zIndex;
background = this.rndColor();
}
if (o.nextSibling) {
o.parentNode.insertBefore(curtain, o.nextSibling);
} else {
o.parentNode.appendChild(curtain);
}
ret = snapshots(box.x, box.y, offsetX, offsetY);
}
if (ret && ctx.isEmbed && ("x" in ctx) && c.width > this.minWidth && c.height > this.minHeight) {
c.width = this.minWidth;
c.height = this.minHeight;
for each(x in [Math.max(ctx.x - this.minWidth, box.oX), Math.min(ctx.x, box.oX + box.oW - this.minWidth)]) {
for each(y in [Math.max(ctx.y - this.minHeight, box.oY), Math.min(ctx.y, box.oY + box.oH - this.minHeight)]) {
ret = snapshots(x, y, offsetX + (x - box.x), offsetY + (y - box.y));
if (!ret) {
offsetX += (x - box.x);
offsetY += (y - box.y);
box.x = x;
box.y = y;
break;
}
}
if (!ret) break;
}
}
if (ctx.debug) {
ret = true;
img2 = tmpImg;
}
if (ret) {
if (curtain) {
if (ctx.debug) {
if (docPatcher.cleanSheet) {
curtain.id = "curtain_" + DOM.rndId();
docPatcher.cleanSheet += " #" + curtain.id + " { opacity: .4 !important }";
}
curtain.style.opacity = ".4"
} else {
curtain.parentNode.removeChild(curtain);
}
snapshots(box.x, box.y, offsetX, offsetY);
}
ctx.img =
{
src: img1,
altSrc: img2,
width: c.width,
height: c.height
}
}
} finally {
if (ctx.isEmbed) docPatcher.blankPositioned(false);
if (curtain && curtain.parentNode) curtain.parentNode.removeChild(curtain);
if (typeof(bgStyle) == "string") dElem.style.background = bgStyle;
docPatcher.opaque(false);
docPatcher.linkAlertHack(false);
docPatcher.fbPresenceHack(false);
if (objClass) objClass.reset();
if (frameClass) frameClass.reset();
if (viewer) viewer.enableRendering = true;
}
return ret;
}
}
function ClassyObj(o) {
this.o = o;
if (o.hasAttribute("class")) this.c = o.className;
}
ClassyObj.prototype = {
o: null,
c: null,
append: function(newC) {
try {
this.o.className = this.c ? this.c + newC : newC;
} catch(e) {}
},
reset: function() {
try {
if (this.c == null) this.o.removeAttribute("class");
else this.o.className = this.c;
} catch(e) {}
}
}
function DocPatcher(ns, o, w) {
this.ns = ns;
this.o = o;
this.win = w;
this.top = w.top;
this.shownCS = " __noscriptShown__" + DOM.rndId();
}
DocPatcher.prototype = {
collectAncestors: function(o) {
var res = [];
for(; o && o.hasAttribute; o = o.parentNode) res.push(new ClassyObj(o));
return res;
},
getRect: function(o, d) {
return (this.getRect = ("getBoundingClientRect" in o)
? function(o) { return o.getBoundingClientRect() }
: function(o, d) {
var b = d.getBoxObjectFor(o);
var x = o.x, y = o.y;
return {
left: x, top: y,
right: x + o.width, left: y + o.height
};
})(o, d)
},
collectPositioned: function(d) {
var t = Date.now();
const w = d.defaultView;
const res = [];
var s = null, p = '', n = null;
const r = this.getRect(this.o, d);
const top = r.top;
const bottom = r.bottom;
const left = r.left;
const right = r.right;
var c = '', b = null;
var hasPos = false;
const posn = [];
const tw = d.createTreeWalker(d, CI.nsIDOMNodeFilter.SHOW_ELEMENT, null, false);
for (var n = null; (n = tw.nextNode());) {
b = this.getRect(n, d);
if (b.bottom < top || b.top > bottom ||
b.right < left || b.left > right)
continue;
s = w.getComputedStyle(n, '');
p = s.position;
if (p == "absolute" || p == "fixed") {
c = " __noscriptPositioned__";
n.__noscriptPos = hasPos = true;
posn.push(n);
} else {
hasPos = hasPos && n.parentNode.__noscriptPos;
if (!hasPos) continue;
c = '';
n.__noscriptPos = true;
posn.push(n);
}
if (s.backgroundImage != "none" || s.backgroundColor != "transparent") {
c += " __noscriptBlank__";
};
if (c) {
res.push(n = new ClassyObj(n));
n.append(c);
}1
}
for each(n in posn) n.__noscriptPos = false;
if(ns.consoleDump & LOG_CLEARCLICK) this.ns.dump("DocPatcher.collectPositioned(): " + (Date.now() - t));
return res;
},
collectOpaqued: function(o, oo) {
if (!oo) oo = { opacity: 1, res: [] };
var w = o.ownerDocument.defaultView;
var opacity;
var co = null;
for(; o && o.hasAttribute; o = o.parentNode) {
opacity = parseFloat(w.getComputedStyle(o, '').opacity);
if (opacity < 1) {
if ((oo.opacity *= opacity) < .3) return []; // too much combined transparency!
oo.res.push(new ClassyObj(o));
}
}
o = w.frameElement;
return o ? this.collectOpaqued(o, oo) : oo.res;
},
forceVisible: function(co) { // TODO: I cause too much reflow, please CHECK ME!
co.append(this.shownCS);
},
forceOpaque: function(co) {
co.append(" __noscriptJustOpaqued__");
},
resetClass: function(co) {
co.reset();
},
_ancestors: null,
_cleanSheetHandle: null,
clean: function(toggle) {
if (toggle) {
if (!this._ancestors) {
this.cleanSheet = "body * { visibility: hidden !important } body ." + this.shownCS.substring(1) + " { visibility: visible !important; opacity: 1 !important }";
this._ancestors = this.collectAncestors(this.o);
}
this._ancestors.forEach(this.forceVisible, this);
this._cleanSheetHandle = this.applySheet(this.cleanSheet);
} else if (this._ancestors) {
this._ancestors.forEach(this.resetClass);
this.removeSheet(this._cleanSheetHandle);
}
},
_positioned: null,
_blankSheetHandle: null,
blankSheet: ".__noscriptPositioned__ * { color: white !important; border-color: white !important; }",
blankPositioned: function(toggle) {
if (toggle) {
this._positioned = this.collectPositioned(this.o.ownerDocument);
this._blankSheetHandle = this.applySheet(this.blankSheet);
} else if (this._positionased) {
this._positioned.forEach(this.resetClass);
this.removeSheet(this._blankSheetHandle);
}
},
_opaqued: null,
opaque: function(toggle) {
if (toggle) {
this._opaqued = this._opaqued || this.collectOpaqued(this.o);
this._opaqued.forEach(this.forceOpaque);
} else if (this._opaqued) {
this._opaqued.forEach(this.resetClass);
}
},
get oldStyle() {
delete this.__proto__.oldStyle;
return this.__proto__.oldStyle = Components.ID('{41d979dc-ea03-4235-86ff-1e3c090c5630}')
.equals(CI.nsIStyleSheetService);
},
applySheet: function(sheet) {
var sheetHandle = null;
if (this.oldStyle) {
// Gecko < 1.9, asynchronous user sheets force ugly work-around
var d = this.o.ownerDocument;
sheetHandle = d.createElementNS(HTML_NS, "style");
sheetHandle.innerHTML = sheet;
d.documentElement.appendChild(sheetHandle);
} else { //
this.ns.updateStyleSheet(sheetHandle = sheet, true);
}
return sheetHandle;
},
removeSheet: function(sheetHandle) {
if (sheetHandle) {
if (this.oldStyle) {
this.o.ownerDocument.documentElement.removeChild(sheetHandle);
} else {
this.ns.updateStyleSheet(sheetHandle, false);
}
}
},
_linkAlertBox: null,
linkAlertHack: function(toggle) {
try {
var w = this.top;
var d = w.document;
if (toggle) {
var box = d.getElementById("linkalert-box");
if (!box || box.style.display) return;
var imgs = box.getElementsByTagName("img");
if (imgs.length > 5) return;
var img;
for (var j = imgs.length; j-- > 0;) {
img = imgs[j];
if (!/^(?:chrome:\/\/linkalert\/skin\/|(?:moz\-icon|file):\/\/)/.test(img.src) || img.naturalWidth == 0 ||
img.offsetWidth > 32 || img.offsetHeight > 32) return;
}
box.style.display = "none";
this._linkAlertBox = box;
} else {
if (this._linkAlertBox) {
this._linkAlertBox.style.display = "";
this._linkAlertBox = null;
}
}
} catch (e) {}
},
_fbPresence: null,
fbPresenceHack: function(toggle) {
if (toggle) {
if (this.top.location.host == "apps.facebook.com") {
var fbPresence = this.top.document.getElementById("presence");
if (fbPresence) {
fbPresence._ccVisibility = fbPresence.style.visibility;
fbPresence.style.visibility = "hidden";
this._fbPresence = fbPresence;
}
}
} else if (this._fbPresence) {
this._fbPresence.style.visibility = this._fbPresence._ccVisibility;
}
}
}